using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal; 

public class Mirror : MonoBehaviour
{
    [Header("Texture/Shader")]
    [Tooltip("Shader property name used by your mirror materials")]
    public string ReflectionSample = "_ReflectionTex";
    [Tooltip("Reflection RT base width (height will follow current camera aspect)")]
    public int m_TextureSize = 256;
    [Range(0.0f, 0.1f)]
    public float m_ClipPlaneOffset = 0.01f;

    [Header("Mirror Plane")]
    [Tooltip("Transform whose 'up' is treated as mirror normal; usually this object itself")]
    public Transform normalTrans;

    [Tooltip("Optional: many small mirrors on the same plane share this manager")]
    public SmallMirrors[] allMirrors = new SmallMirrors[0];

    public enum AntiAlias { X1 = 1, X2 = 2, X4 = 4, X8 = 8 }
    public AntiAlias MSAA = AntiAlias.X1;

    [Header("Culling & Layers")]
    public bool useDistanceCull = false;
    public float m_maxDistance = 50f; // meters
    public bool enableSelfCullingDistance = true;
    public float[] layerCullingDistances = new float[32];
    [Tooltip("Which layers are rendered into the reflection")]
    public LayerMask m_ReflectLayers = ~0; // everything

    // --- runtime ---
    public static bool s_InsideRendering = false;

    private float m_SqrMaxdistance;
    private int _propReflectionTex = -1;

    private Renderer _renderer;
    private readonly List<Material> _allMats = new List<Material>();

    private Camera _reflectionCam;
    private Transform _refT;

    private RenderTexture _reflectionRT;
    private float _rtAspectFromCam = 1.0f;  // height/width

    private bool _srpHooked = false;
    private int _lastFrameRendered = -1;

    // convenience
    private static bool UsingSRP() => GraphicsSettings.currentRenderPipeline != null;

    // ----------------- Unity lifecycle -----------------

    private void Awake()
    {
        _propReflectionTex = Shader.PropertyToID(ReflectionSample);

        if (!normalTrans)
        {
            normalTrans = new GameObject("Normal Trans").transform;
            normalTrans.position = transform.position;
            normalTrans.rotation = transform.rotation;
            normalTrans.SetParent(transform, worldPositionStays: true);
        }

        _renderer = GetComponent<Renderer>();
        if (!_renderer || _renderer.sharedMaterials == null || _renderer.sharedMaterials.Length == 0)
        {
            Debug.LogWarning("[Mirror] Renderer/material missing, self-destroyed.");
            Destroy(this);
            return;
        }

        // Collect materials from this renderer + all small mirrors
        CollectAllMaterials();

        // Create reflection camera + RT
        CreateOrEnsureReflectionCamera();
        CreateOrResizeRT(null); // initial RT based on current screen aspect (fallback until a camera arrives)

        // Prime materials
        SetTextureOnAllMaterials(_reflectionRT);
    }

    private void OnEnable()
    {
        SetTextureOnAllMaterials(_reflectionRT);

        if (UsingSRP() && !_srpHooked)
        {
            RenderPipelineManager.beginCameraRendering += SRP_BeginCameraRendering;
            _srpHooked = true;
        }
    }

    private void OnDisable()
    {
        if (_srpHooked)
        {
            RenderPipelineManager.beginCameraRendering -= SRP_BeginCameraRendering;
            _srpHooked = false;
        }
    }

    private void OnDestroy()
    {
        if (_reflectionRT) DestroyImmediate(_reflectionRT);
        if (_reflectionCam) DestroyImmediate(_reflectionCam.gameObject);
    }

    // 内置管线 fallback：仅当未使用 SRP 时启用
    public void OnWillRenderObject()
    {
        if (UsingSRP()) return; // SRP 下用回调

        Camera cam = Camera.current;
        if (!cam || cam.orthographic || !_renderer || !_renderer.enabled) return;

        if (s_InsideRendering || _lastFrameRendered == Time.frameCount) return;

        if (useDistanceCull)
        {
            float sqr = (normalTrans.position - cam.transform.position).sqrMagnitude;
            if (sqr > m_SqrMaxdistance) return;
        }

        // 在镜面背面则不渲
        Vector3 localPos = normalTrans.worldToLocalMatrix.MultiplyPoint3x4(cam.transform.position);
        if (localPos.y < 0) return;

        s_InsideRendering = true;
        RenderReflectionForCamera_Builtin(cam);
        s_InsideRendering = false;
        _lastFrameRendered = Time.frameCount;
    }

    // ----------------- SRP path (URP/HDRP) -----------------
    private void SRP_BeginCameraRendering(ScriptableRenderContext context, Camera currentCam)
    {
        // 忽略：反射相机自身、非游戏相机、正交相机、当前不可见等
        if (s_InsideRendering || currentCam == _reflectionCam) return;
        if (currentCam.cameraType != CameraType.Game && currentCam.cameraType != CameraType.SceneView) return;
        if (currentCam.orthographic) return;
        if (!_renderer || !_renderer.enabled || !_renderer.isVisible) return;
        if (_lastFrameRendered == Time.frameCount) return; // 同帧去重（多个可见镜子时可按需去掉）

        if (useDistanceCull)
        {
            float sqr = (normalTrans.position - currentCam.transform.position).sqrMagnitude;
            if (sqr > m_SqrMaxdistance) return;
        }

        // 背面不渲
        Vector3 localPos = normalTrans.worldToLocalMatrix.MultiplyPoint3x4(currentCam.transform.position);
        if (localPos.y < 0) return;

        s_InsideRendering = true;

        // 同步参数/RT 尺寸
        CreateOrResizeRT(currentCam);
        SyncReflectionCameraCommon(currentCam);

        // 设置镜像位姿 + 斜截体投影
        SetupReflectionViewAndProjection(currentCam);

        // 渲染（URP 合法入口）
        GL.invertCulling = true;
        try
        {
            UniversalAdditionalCameraData data =
                _reflectionCam.gameObject.GetComponent<UniversalAdditionalCameraData>()
                ?? _reflectionCam.gameObject.AddComponent<UniversalAdditionalCameraData>();
            data.renderShadows = false;
            data.requiresColorTexture = false;
            data.requiresDepthTexture = false;

            UniversalRenderPipeline.RenderSingleCamera(context, _reflectionCam);
        }
        finally
        {
            GL.invertCulling = false;
        }

        _lastFrameRendered = Time.frameCount;
        s_InsideRendering = false;
    }

    // ----------------- Helpers -----------------

    private void CollectAllMaterials()
    {
        _allMats.Clear();

        foreach (var m in _renderer.sharedMaterials)
            if (m && !_allMats.Contains(m)) _allMats.Add(m);

        if (allMirrors != null)
        {
            for (int i = 0; i < allMirrors.Length; ++i)
            {
                if (!allMirrors[i]) continue;
                allMirrors[i].manager = this;
                var r = allMirrors[i].GetRenderer();
                if (!r) continue;
                foreach (var m in r.sharedMaterials)
                    if (m && !_allMats.Contains(m)) _allMats.Add(m);
            }
        }
    }

    private void CreateOrEnsureReflectionCamera()
    {
        if (_reflectionCam) return;

        var go = new GameObject("MirrorCam", typeof(Camera));
        go.hideFlags = HideFlags.HideAndDontSave;
        go.transform.SetParent(normalTrans, worldPositionStays: true);
        go.transform.localPosition = Vector3.zero;
        go.transform.localRotation = Quaternion.identity;

        _reflectionCam = go.GetComponent<Camera>();
        _reflectionCam.enabled = false;            // 由我们手动驱动
        _reflectionCam.useOcclusionCulling = false;
        _reflectionCam.allowHDR = true;
        _reflectionCam.allowMSAA = true;
        _reflectionCam.clearFlags = CameraClearFlags.Skybox; // 或 Color，随需
        _reflectionCam.cullingMask = (~(1 << 4)) & m_ReflectLayers.value; // 排 Layer4（常见 Water）

        if (enableSelfCullingDistance)
            _reflectionCam.layerCullDistances = layerCullingDistances;
        _reflectionCam.layerCullSpherical = enableSelfCullingDistance;

        _refT = _reflectionCam.transform;
        m_SqrMaxdistance = m_maxDistance * m_maxDistance;
    }

    private void CreateOrResizeRT(Camera srcCam)
    {
        // 依据源相机像素比，反射 RT 高度 = 宽度 * (H/W)
        float aspect = (srcCam && srcCam.pixelWidth > 0)
            ? (float)srcCam.pixelHeight / Mathf.Max(1, srcCam.pixelWidth)
            : (float)Screen.height / Mathf.Max(1, Screen.width);
        aspect = Mathf.Clamp(aspect, 0.1f, 10f);

        int w = Mathf.Clamp(m_TextureSize, 1, 4096);
        int h = Mathf.Max(1, Mathf.RoundToInt(w * aspect));

        bool msaaChanged = (_reflectionRT && _reflectionRT.antiAliasing != (int)MSAA);
        bool needNew = _reflectionRT == null || _reflectionRT.width != w || _reflectionRT.height != h || msaaChanged;

        if (!needNew) return;

        if (_reflectionRT) DestroyImmediate(_reflectionRT);

        var fmt = SystemInfo.SupportsRenderTextureFormat(RenderTextureFormat.ARGBHalf)
            ? RenderTextureFormat.ARGBHalf : RenderTextureFormat.ARGB32;

        _reflectionRT = new RenderTexture(w, h, 24, fmt, RenderTextureReadWrite.Default)
        {
            name = $"ReflectionTex_{GetInstanceID()}",
            isPowerOfTwo = true,
            filterMode = FilterMode.Trilinear,
            antiAliasing = (int)MSAA
        };

        _reflectionCam.targetTexture = _reflectionRT;
        SetTextureOnAllMaterials(_reflectionRT);
        _rtAspectFromCam = aspect;
    }

    private void SetTextureOnAllMaterials(RenderTexture target)
    {
        if (target == null) return;
        foreach (var m in _allMats)
            if (m) m.SetTexture(_propReflectionTex, target);
    }

    private void SyncReflectionCameraCommon(Camera src)
    {
        _reflectionCam.cullingMask = (~(1 << 4)) & m_ReflectLayers.value;
        _reflectionCam.fieldOfView = src.fieldOfView;
        _reflectionCam.aspect = src.aspect;
        _reflectionCam.orthographic = false;
        _reflectionCam.nearClipPlane = Mathf.Max(0.01f, src.nearClipPlane);
        _reflectionCam.farClipPlane = src.farClipPlane;

        if (enableSelfCullingDistance)
            _reflectionCam.layerCullDistances = layerCullingDistances;
        _reflectionCam.layerCullSpherical = enableSelfCullingDistance;
    }

    private void SetupReflectionViewAndProjection(Camera src)
    {
        // 反射相机的“相对 normalTrans”的局部位姿（你原有的做法）
        var camT = src.transform;

        // 位置：对称
        Vector3 localPos = normalTrans.worldToLocalMatrix.MultiplyPoint3x4(camT.position);
        localPos.y *= -1f;
        _refT.localPosition = localPos;

        // 朝向：对称（翻转 x/z 欧拉）
        _refT.eulerAngles = camT.eulerAngles;
        var e = _refT.localEulerAngles; e.x *= -1f; e.z *= -1f; _refT.localEulerAngles = e;

        // 反射矩阵 + 斜截体
        Vector3 n = normalTrans.up;
        Vector3 p = normalTrans.position;
        float d = -(n.x * p.x + n.y * p.y + n.z * p.z) - m_ClipPlaneOffset;
        Vector4 reflectionPlane = new Vector4(n.x, n.y, n.z, d);

        Matrix4x4 reflection = Matrix4x4.identity;
        CalculateReflectionMatrix(ref reflection, ref reflectionPlane);

        Matrix4x4 ref_WorldToCam = src.worldToCameraMatrix * reflection;
        _reflectionCam.worldToCameraMatrix = ref_WorldToCam;

        Vector4 clipPlane = CameraSpacePlane(ref ref_WorldToCam, ref p, ref n);
        _reflectionCam.projectionMatrix = src.CalculateObliqueMatrix(clipPlane);
    }

    // --------- Built-in fallback rendering (only runs when NOT using SRP) ---------
    private void RenderReflectionForCamera_Builtin(Camera src)
    {
        CreateOrResizeRT(src);
        SyncReflectionCameraCommon(src);
        SetupReflectionViewAndProjection(src);

        GL.invertCulling = true;
        try
        {
            _reflectionCam.Render();
        }
        finally
        {
            GL.invertCulling = false;
        }
    }

    // ----------------- Math helpers -----------------

    private static float Dot(ref Vector3 left, ref Vector3 right)
    {
        return left.x * right.x + left.y * right.y + left.z * right.z;
    }

    private Vector4 CameraSpacePlane(ref Matrix4x4 worldToCamera, ref Vector3 pos, ref Vector3 normal)
    {
        Vector3 offsetPos = pos + normal * m_ClipPlaneOffset;
        Vector3 cpos = worldToCamera.MultiplyPoint3x4(offsetPos);
        Vector3 cnormal = worldToCamera.MultiplyVector(normal).normalized;
        return new Vector4(cnormal.x, cnormal.y, cnormal.z, -Dot(ref cpos, ref cnormal));
    }

    private static void CalculateReflectionMatrix(ref Matrix4x4 reflectionMat, ref Vector4 plane)
    {
        // plane: (a,b,c,d) with ax + by + cz + d = 0
        reflectionMat.m00 = (1F - 2F * plane[0] * plane[0]);
        reflectionMat.m01 = (-2F * plane[0] * plane[1]);
        reflectionMat.m02 = (-2F * plane[0] * plane[2]);
        reflectionMat.m03 = (-2F * plane[3] * plane[0]);

        reflectionMat.m10 = (-2F * plane[1] * plane[0]);
        reflectionMat.m11 = (1F - 2F * plane[1] * plane[1]);
        reflectionMat.m12 = (-2F * plane[1] * plane[2]);
        reflectionMat.m13 = (-2F * plane[3] * plane[1]);

        reflectionMat.m20 = (-2F * plane[2] * plane[0]);
        reflectionMat.m21 = (-2F * plane[2] * plane[1]);
        reflectionMat.m22 = (1F - 2F * plane[2] * plane[2]);
        reflectionMat.m23 = (-2F * plane[3] * plane[2]);

        reflectionMat.m30 = 0F;
        reflectionMat.m31 = 0F;
        reflectionMat.m32 = 0F;
        reflectionMat.m33 = 1F;
    }

    // 公开一个给外部调用（例如 SmallMirrors 在 Awake 后刷新贴图）
    public void SetTexture(RenderTexture target)
    {
        SetTextureOnAllMaterials(target);
    }

    // 供 Inspector 调整时更新
    private void OnValidate()
    {
        m_TextureSize = Mathf.Clamp(m_TextureSize, 1, 4096);
        m_ClipPlaneOffset = Mathf.Clamp(m_ClipPlaneOffset, 0f, 0.1f);
        m_SqrMaxdistance = m_maxDistance * m_maxDistance;

        if (_reflectionCam != null)
        {
            CreateOrResizeRT(null);
            SetTextureOnAllMaterials(_reflectionRT);
        }
    }
}
